SQL基础培训

SQL基础培训专题

 

培训目标:了解SQL(select,update,insert)的基本写法、复杂写法,

     在有索引的情况下,如何写出高效的SQL。

 

 

 

第一章实例环境一描述

  学生成绩管理系统

课程信息表 xj_course(CrsID,CrsName, CrsNote )

学生信息表 xj_stu   (StuID, ClsID, StuName, Birthday, Address, Tel, City )

教师信息表 xj_tea   (TeaID, TeaName, address )

分数表     xj_score (StuID, ClsID, CrsID, TeaID, score )

课程所属关系信息表 xj_clscrs(ClsID, CrsID,TeaID)

 

 

 

建立环境实例

  环境的建立:

 MySQL 4.1.10a-max-log, DB2版本。

 


第二章基本SQL语法介绍

2.1       Select

  最基本的语句,MySQL的语法为:

 Select  [ All | Distinct ]select_list

       [ into outFile ‘FileName’ export_options |into dumfile ‘fileName’]

  From tabl_list

   [Wherewhere_expr ]

  [Group by Column desc|asc]

   [Having where_expr]

  [Order by ColName asc|desc ]

   [limit n,m]

  [For update |Lock in share mode]

 2.1.1,distinct 是控制返回的数据重复行的。

  selectdistinct City ,ClsID    From xj_stu

select distinct ClsID   Fromxj_stu

2,into 选项能把这个结果导出到外面的文本文件中。

  mysql>select * into outfile 'wangxl.txt' From xj_stu ;

Query OK, 27 rows affected (0.00 sec)

 

mysql> select * into dumpfile'xj_stu.txt' From xj_stu ;

ERROR 1172 (42000): Result consisted ofmore than one row

mysql> select * into dumpfile'xj_stu.txt' From xj_stu where stuid='STU001' ;

Query OK, 1 row affected (0.00 sec)

[root@fxs001 /]# find / -name"xj_stu.txt"

/usr/local/mysql-max-4.1.10a-pc-linux-gnu-i686/data/sqldb/xj_stu.txt

3,From tabl_list 列举要检索的数据表或者子查询。

  这里要讲究的东西还挺多的,

  A,可以设置别名: From xj_stu S, xj_Cls C 。别名别重复、别是关键字就行。

  B,可以把一个子查询当作一个表。select * From  (select distinct ClsID   From xj_stu ) a 。

    其实放在 From 后面的东西别理解成表,直接理解成一个结果集,一个通过各种手段

构造的子查询,这样就为写很多复杂的SQL作意识上的准备。

  C,联合查询,就在这个中间体现了,一般的有:

   tableA A inner join tableB B on A.ID = B.ID   两个都有的来连接。去掉inner也一样。

   tableA A left outer join tableB on A.ID = B.ID  A中所有的连接起来,去掉outer也一样。

  D,USE/IGNORE/FORCE INDEX 来特别提醒MySQL来进行有些索引得取舍。

4,where 子句

  是用来限定条件或者建立 表、子查询关联的语句。

5,limit 分页中常用

 LIMIT 子句可以被用于强制SELECT 语句返回指定的记录数。LIMIT接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1):

 mysql> SELECT * FROM table LIMIT 5,10;  # 检索记录行 6-15

为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:

 mysql> SELECT * FROM table LIMIT 95,-1; # 检索记录行 96-last.

如果只给定一个参数,它表示返回最大的记录行数目:

mysql> SELECT * FROM table LIMIT 5;     # 检索前 5 个记录行

换句话说,LIMIT n 等价于 LIMIT 0,n。

6,Group by

 是用来进行统计分组合计的功能,后面接要进行统计分组的字段或者表达式。

 

Count(*)

返回由一个 SELECT 语句检索出来的记录行中非 NULL 值的记录总数目:

insert into xj_cls values('9999','tempClass')

select count(S.ClsID)  From xj_stu S left    join  xj_cls C on S.ClsID =C.ClsID  #28

select count(ClsName)  From xj_stu S left    join  xj_cls C on S.ClsID =C.ClsID #27

select count(*)  From xj_stu S left    join  xj_cls C on S.ClsID =C.ClsID        #28

 

COUNT(DISTINCT expr,[expr...])

返回一个互不相同的非NULL 的值的总数目:

select count(distinct stuid ) From xj_score; 27

select count(* ) From xj_score ; 81

 

 

在 MySQL 中,通过给出一个表达式列表,可以得到不包含 NULL 的不同的表达式组合的数目。

 

AVG(expr)

返回 expr 的平均值:

select stuID,avg(score)  From xj_score   Group by StuID ; 

select stuID,avg(score)  From xj_score where stuid=’12345’  Group by StuID ; (结果条数为0)

 

 

MIN(expr)

MAX(expr)

返回 expr 的最小或最大值。MIN() 和 MAX() 可以接受一个字符串参数;在这种情况下,它们将返回最小或最大的字符串传下。查看章节 5.4.3 MySQL 如何使用索引。

select stuID,min(score),max(score)  From xj_score   Group by StuID

 

SUM(expr)

返回 expr 的总和。注意,如果返回集中没有从我任何记录行,它将返回 NULL !

select sum(score) From xj_score whereStuID='001001'

select sum(score) From xj_score whereStuID='001001'  Group by StuID

 

7,Order by 排序

   可以指定多个字段排序,可以指定别名、需要进行排序,也可以进行表达式进行排序。

  如果继续排序的结果比较多,MySQL会利用 临时文件进行排序。

例如:

select * From xj_stu whereClsID='CL001' 

 Order by   (case when StuName='zz'then '00000' else StuID end )

 就是要把 学生zz排在第一位,其他的按照学号来排列。

 

2.2       MySQL用于select 和where 子句的函数介绍

http://www.phpe.net/mysql_manual/06-3.html#Other_Functions

大家可以自己去看,如果不属性的话,最好每个都动手写一个sql来试一下,加深一下感情。

这里只列举几个常用的,

 

(Case when then  when ..then else end )

select stuID ,( case when  score >=90 then 'A' 

                       when score >= 80 andscore <90 then 'B'

                       when score >= 70 andscore <80 then 'C'

                       when score <70  then 'D' 

            end ) Grad,score

From xj_score

 

统计一下班级 CL001班的分数中,各个等级的人数分布,

select ( case when  score >=90 then 'A' 

                       when score >= 80 andscore <90 then 'B'

                       when score >= 70 andscore <80 then 'C'

                       when score <70  then 'D' 

            end ) Grad ,count(*)

From xj_score

where ClsID='CL001'

Group by 1

Grad    count(*)   

 ------- -----------

 A       3          

 B       6          

 C       3          

 D       7       

 

换一个格式显示一下,这个格式 叫做 “中国财务习惯”,很多地方用到。。

select ClsID,

sum(( case when  score >=90 then 1  else 0 end )) A ,

sum(( case when  score >= 80 and score <90  then 1 else 0 end )) B ,

sum(( case when  score >= 70 and score <80  then 1 else 0 end )) C ,

sum(( case when  score <= 70                              then 1  else 0 end )) D                   

From xj_score

Group by ClsID

ClsID    A     B     C    D   

 -------- ----  ----  ---- ----

 CL001    3     6     3    7   

 CL002    6     5     3    10  

 CL003    3     3     3    6   

 CL004    5     4    6     6   

 

其实就是传说中的 竖的格式转横的格式。

 

第三章 这个学籍管理系统中可能用到的统计需求

要做统计得首先完全清楚这个数据库的设计。请大家再次熟悉一下这个简单的数据库结构。

统计一下 各个班级的人数并列举一下来自哪里

Select ClsID,count(*) Cnt  ,Group_concat(distinct City) CitySS

From xj_stu

Group by ClsID  

ClsID    Cnt     CitySS        

 --------  ------ --------------

 CL001    7       dl            

 CL002    8       bj,dl,shanghai

 CL003    5       dl,tj         

 CL004    7       dl,shyang     

 CL999    1       dalian  

 

注意一下 这里的 Group_concat 函数是MySQL特有的,别的数据库没有,得自己写函数来完成这个列到行得转换。

 

2.3       统计参加考试的学生的均分在 85分以上的人的清单

select stuID,avg(score) avgScore Fromxj_score sc

where score >=85

Group by stuID

Order by 2 desc

 

看看 和下面的有什么区别:

select stuID,avg(score) avgScore Fromxj_score sc

Group by stuID

having avg(score) >=85

Order by 2 desc

 

哪个是正确的 ??

 

2.4       列一下各班级各科目分数的前3名。

要求结果为:班级、学号、姓名、科目名称、成绩、名次 。

 

selecta.ClsID,a.stuID,stuName,CrsName,a.score,rank From (

select ClsID,CrsID,stuID,score ,(selectcount(*) From xj_score s2 where s2.ClsID=s1.ClsID and s2.CrsID=s1.CrsID ands2.score >=s1.score) Rank

 Fromxj_score s1

) a ,xj_stu s,xj_course cc

where Rank <=3 and s.stuID=a.stuID andcc.crsID = a.crsID

Order by a.ClsID,a.CrsID,rank

 

“名次” 就是排行第几的意思,在MySQL中是弱项,需要通过嵌套子查询来实现,

在 DB2,Orace 中可以使用 分析函数 rank() OVER ( partitionby  ClsID,CrsID ORDER BY Score desc) 或者 dense_rank() OVER ( partitionby  ClsID,CrsID ORDER BY Score desc) 来实现,这个 rank() 和 dense_rank() 是非常有用的分析函数,在很多时候能解决很多棘手的问题。

 

课外思考:如何用一个SQL来 找出一个用户流水账户中断档的记录。

表:T_Cash表(CashID,CustomerID,CashAmount,CashBalace)

CID         CUSTOMER_ID     CASHFLOW_AMOUNT     CASH_BALANCE   

ASH00000035  70705813        -800                        1054228        

ASH00000076  70705813        -800                        1053428        

 ASH00000554 70705813        15200                       1068542        

 ASH90001822 70705813        314                         1053742        

 ASH90001823 70705813        -416                        1053326        

 ASH90001824 70705813        314                         1053640        

 ASH90001825 70705813        -416                        1053224        

 ASH90001826 70705813        -416                        1052808        

 ASH90001827 70705813        314                         1053122        

 

注意看 CASH_BALANCE 字段的内容是不断变化的,变化的量是当前那条记录的 CashFlowAmount的值, 如果 上图中 红字的那条记录没了,你有什么方法来检查出来是哪条前后的数据对不上了?(可以用 Rank() (只Db2/Oracle中) ,也可以用子查询来做)

 

2.5       找出没有参加考试的学生清单。

要求结果为:班级、学号、姓名、缺考科目 。

思路分析,首先得构造一个应该考试的清单,它表示全部应该考的内容,然后和已经考试的结果进行左外连接,如果没有匹配到的就是没有考的内容。

 

select Al.* From

(select s.ClsID,s.StuID,s.StuName,cc.CrsIDFrom xj_stu s,xj_clscrs cc

where s.ClsID=cc.ClsID ) Al left joinxj_score sc on Al.CrsID=sc.crsID and Al.stuID=sc.stuID and Al.ClsID =sc.ClsID

where sc.Stuid is null

ClsID    StuID     StuName     CrsID   

 -------- --------  ----------  --------

 CL001    STU001    zhangyi     Crs001  

 CL001    STU002    zhzhb       Crs001  

 

 

2.6       统计各个班级参加考试的平均分,按照平均分从高到低。

要求结果:班级号、平均分

 

select clsID,avg(score) From xj_score

Group by ClsID

order by 2 desc

clsID    avg(score)   

 -------- -------------

 CL004    76.007619    

 CL002    73.906667    

 CL003    73.885333    

 CL001    73.658421    

2.7       统计本次考试各科成绩的及格率,按照及格率从高到低排序。

其实就是分析一下本次考试的整体难度程度,

格式1:科目、及格人数、总考试人数、平均分、及格率。(3行数据)

 

select sc.CrsID,

    cc.CrsName,

    sum(case when sc.score>=60 then 1 else 0 end) GCnt,

    count(*) CntTotal,

    avg(sc.score) avgScore,

    sum(case when sc.score>=60 then 1 else 0 end)/Count(*) GCntPercent

From xj_score sc,

    xj_course cc

where        sc.CrsID =cc.CrsID

Group by   sc.CrsID

Order by    GCntPercent desc

 

 

 

 CrsID     CrsName    GCnt     CntTotal     avgScore     GCntPercent   

 --------  ---------- -------  -----------  ----------- --------------

 Crs003    English    24       27           75.31963     0.89          

 Crs001    Chinese    17       25           72.3864      0.68          

 Crs002    Maths      18       27           75.348889    0.67          

 

格式2:语文及格人数、平均分、及格率,数学及格人数、平均分、及格率,英语及格人数、平均分、及格率。

 

select

max(Case when CrsName='Chinese' then GCnt else 0 end ) ChGCnt,

max(Case when CrsName='Chinese' then avgScore else 0 end) ChAvg,

max(Case when CrsName='Chinese' then GCntPercent else 0 end )ChGPercent,

max(Case when CrsName='Maths' then GCnt else 0 end ) MaGCnt,

max(Case when CrsName='Maths' then avgScore else 0 end) MaAvg,

max(Case when CrsName='Maths' then GCntPercent else 0 end )MaGPercent,

max(Case when CrsName='English' then GCnt else 0 end ) EnGCnt,

max(Case when CrsName='English' then avgScore else 0 end) EnAvg,

max(Case when CrsName='English' then GCntPercent else 0 end )EnGPercent

 

 From (

select sc.CrsID,

    cc.CrsName,

    sum(case when sc.score>=60 then 1 else 0 end) GCnt,

    count(*) CntTotal,

    avg(sc.score) avgScore,

    sum(case when sc.score>=60 then 1 else 0 end)/Count(*) GCntPercent

From xj_score sc,

    xj_course cc

where        sc.CrsID =cc.CrsID

Group by   sc.CrsID

) a

 

ChGCnt    ChAvg     ChGPercent     MaGCnt    MaAvg      MaGPercent     EnGCnt    EnAvg     EnGPercent   

 --------- --------  -------------  --------- ---------  -------------  --------- --------  -------------

 17        72.3864   0.68           18         75.348889  0.67          24         75.31963  0.89         

 

 1record(s) selected [Fetch MetaData: 0/ms] [Fetch Data: 0/ms]

 

 

 

2.8       年级排名

 学号、姓名、语文、数学、英语、平均分、年级名次 (如果有一门没有考则单科算0分)

做法有很多,以下是其中的一种:

 

selectHA.STUID,HA.STUNAME,HA.CHSCORE,HA.MASCORE,HA.ENSCORE,HB.AVGSCORE,HB.RANK

From

(

select

 sc.stuID,s.StuName,

sum((case when cc.CrsName='Chinese' then score else 0 end )) Chscore,

sum((case when cc.CrsName='Maths' then score else 0 end )) Mascore,

sum((case when cc.CrsName='English' then score else 0 end )) Enscore

 Fromxj_score sc,xj_course cc,xj_stu s

where sc.CrsID =cc.CrsID and sc.StuID =s.StuID

Group by sc.stuID,s.StuName

 )  HA, (

select A.stuID,A.avgScore,(

  select count(*) From (select sc.stuID,sum(sc.score)/3  avgScore From xj_score sc

Group by sc.StuID ) aa where A.avgScore<=aa.avgScore) Rank

 From

(select sc.stuID,sum(sc.score)/3  avgScore From xj_score sc

Group by sc.StuID ) A  ) HB

where HA.stuID = HB.stuID

Order by HB.Rank

 

 

 

 

 

第四章 笛卡尔积的危害和利用

什么是笛卡尔积

 就是有20条记录的A集合与30条集合的B集合进行关联,结果因为“一不小心”没有指定关联关键字,那么数据库将用两两组合的形式把最终的结果集返回出来,那么返回的结果就是 20 * 30 =600 条。这个“一不小心”的极端情况就是 一个 1万条记录和另一个50万条记录“不小心”进行了笛卡尔积 那就是 50亿条记录,这个对于任何一个数据库来说都是灾难。。。。。

  所以写SQL的时候,一定要注意,在表关联的时候,一定要指定能唯一关联的关键字。。

  记住的要诀就是 1,一定要关联!2,一定要有一方是唯一的关键字。

  一方是唯一的话,那么就是 N * 1 的结果,比较正常。

 

但有的时候,为了统计的需要,也可以人为的构造这样 N * n 的结果,N是指大的结果集合,n是指特定那么几个常量。

我们来看这个例子:

 

create table vvList  (Code Varchar(20),Amount decimal(10,2))

drop table CODETYPE  ;

drop table vvList  ;

Create table CODETYPE   (Code varchar(10),Name varchar(20) )

select * From CashValue

insert into CODETYPE  values ('A','吃' ) ;

insert into CODETYPE  values ('A01','蔬菜' ) ;

insert into CODETYPE  values ('A02','水果' ) ;

insert into CODETYPE  values ('A03','点心' ) ;

insert into CODETYPE  values ('B','穿' ) ;

insert into CODETYPE  values ('B01','冬衣' ) ;

insert into CODETYPE  values ('B02','夏衣' ) ;

insert into CODETYPE  values ('B03','秋衣' ) ;

insert into CODETYPE  values ('B0301','夹克' ) ;

delete from vvList  ;

insert into vvList  values ('A0101',1) ;

insert into vvList   values ('A0102',2) ;

insert into vvList   values ('A0103',3) ;

insert into vvList   values ('A0201',4) ;

insert into vvList  values ('A0202',5) ;

insert into vvList  values ('A0203',6) ;

insert into vvList  values ('B0101',7) ;

insert into vvList   values ('B0102',8) ;

insert into vvList  values ('B0103',9) ;

insert into vvList  values ('B0201',11) ;

insert into vvList   values ('B0203',17) ;

insert into vvList   values ('B0204',788) ;

 

 

select substr(Code,1,D.DD) ,

       sum(Amount)

       From vvList ,

       (select distinct length(Code) DD From CODETYPE

        union

         select 0         ) D

group by substr(Code,1,D.DD)

substr(Code,1,D.DD)     sum(Amount)   

 ----------------------  --------------

                         861           

 A                       21            

 A01                     6              

 A0101                   1             

 A0102                   2             

 A0103                   3             

 A02                     15            

 A0201                   4             

 A0202                   5             

 A0203                   6             

 B                       840           

 B01                     24            

 B0101                   7             

 B0102                   8             

 B0103                   9             

 B02                    816           

 B0201                   11            

 B0203                   17            

 B0204                   788           

 

 19record(s) selected [Fetch MetaData: 0/ms] [Fetch Data: 0/ms]

 

 [Executed: 07-11-1下午11时49分39秒 ] [Execution:94/ms]

 

这样的结果 在 DB2中有个group byrollup 可以达到类似的功能:

selectsubstr(Code,1,1),substr(Code,1,3),Code,sum(Amount) From vvList

Group byrollup(substr(Code,1,1),substr(Code,1,3),Code)

1    2     3      4   

 ---- ----  -----  ----

 All  ALL   ALL    861 

 A    ALL   ALL    21  

 B    ALL   ALL    840 

 A    A01   ALL    6   

 A    A02   ALL    15  

 B    B01   ALL    24  

 B    B02   ALL    816 

 A     A01   A0101  1   

 A     A01   A0102  2   

 A     A01   A0103  3   

 A     A02   A0201  4   

 A     A02   A0202  5   

 A     A02   A0203  6   

 B    B01   B0101  7   

 B    B01   B0102  8   

 B    B01   B0103  9   

 B    B02   B0201  11  

 B    B02   B0203  17  

 B    B02   B0204  788 

 

 19record(s) selected [Fetch MetaData: 0/ms] [Fetch Data: 78/ms]

 

 [Executed: 07-11-1下午11时47分32秒 ][Execution: 110/ms]

也能达到类似的结果。

 

 

再来思考下面一个任务,是我们实际工作遇到的,

用户表:Customer(CustomerID) 有50000条记录。

用户配置表:T_LV(SEQ decimal(20,0),CustomerID,ProductID varchar(10))

  这个表的特征是每个用户都有一条Product_ID在这里面,现在想增加另一个Product_ID(’T002’)到这个表中,问:如何来用 insert 语句来增加。

注意,是要增加 50000条记录,而且这个seq 不是自增长的,是从原有基础上逐一累加的。

 

insert into T_LV select T.SEQ +TT.CC,C.CustomerID,'T006' From Cust C,(select Max(Seq)  SEQ From T_LV) T,

(select C1.CustomerID,count(*) CC From CustC1,Cust C2 where C1.CustomerID >=C2.CustomerID group by C1.CustomerID) TT

                              whereC.CustomerID = TT.CustomerID

 

 

 

以是表结构和数据:

id                   a_id                   b_id                 flag

 

001                 a001                   b001                     Y

002                 a001                  b002                     N

003                 a002                  b001                     Y

004                 a002                  b002                     Y

 

其中   id,a_id,b_id是主键,

现在要查a_id的个数,要求是:查flag是Y的,重复的算一个,如果相同a_id的不同记录中有N的,不计算入个数。

比如上面的记录中,a001记录中有一条记录flag是N,所以不算,a002中有两条记录,并且falg都是Y,算一条。

则结果应只有1条.

1)

SELECT        COUNT(DISTINCTA.A_ID) AID

FROM    T1

WHERE        a.FLAG= 'Y'

and        NOTEXISTS (SELECT      1

       FROM   T1 B

       WHERE       A.A_ID = B.A_ID

       AND     B.FLAG = 'N')

2)

Select     count(*)

From      (select   count(a_id) d

       from     taby

       groupby        a_id having min(flag)= 'Y') a;

3)

select      sum(Y*N)

From      (select   A_ID,

              max((casewhen Flag = 'Y' then 1 else -99 end)) Y,

              min((casewhen Flag = 'N' then 0 else 1 end)) N

       From     taby

       Groupby       A_ID) d

 

 

分页技术,

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 SQL基础 1.1 基本概念 结构化查询语言(Structured Query Language)简称SQL,是一种关系数据库查询语言,用于存取数据以及查询、更新和管理关系数据库系统。 1.2 语句结构 1.2.1 数据查询语言(DQL) 对数据库进行的信息查询,select。 1.2.2 数据操作语言(DML) 用于操作关系型数据库对象内部的数据,insert、update、delete。 1.2.3 数据定义语言(DDL) 用来建立及定义数据表、字段以及索引数据库结构,create、alter、drop 。 1.2.4 数据控制语言(DCL) 用于控制对数据库数据的访问,通常用于创建与用户访问相关的对象以及控制用户的权限,grant、revoke(撤销)。 1.2.5 事务控制命令(TPL) 用于管理数据库事务,commit、rollback、savepoint(在一组事务里创建标记点以用于回退)。 1.3 表的构成 1.3.1 字段 字段是表里的一列,用于保持每条记录的特定信息 1.3.2 记录 记录,也被成为一行数据,是表里的每一行 1.4 完整性的约束条件 1.4.1 实体完整性 关系模型的实体完整性在create table中用primary key约束实现,primary key约束用于定义主键,它保证主键的唯一性和非空性。 1.4.2 参照完整性 关系模型的参照完整性可以通过在create table中用foreign key (<外键>) references <被参照表名> (<与外键对应的主键名>)进行约束定义。 1.4.3 用户定义完整心 在create table语句中可以根据应用要求,定义属性以及元组上的约束。 常见的用户定义的完整性约束有: not null或null约束。 unique约束:唯一性约束。 default约束:默认值约束。 check约束:检查约束,check约束通过约束条件表达式设置列值应该满足的条件。 1.5 范式 1.5.1 第一范式 1.5.1.1 规范 无重复的列,确保每列保持原子性,即数据库表中的所有字段值都是不可分解的原子值。 1.5.1.2 举例 姓名 年龄 联系电话 地址 省 市 详细地址 1.5.2 第二范式 1.5.2.1 规范 属性完全依赖于主键,确保表中每列都与主键相关。 1.5.2.2 举例 订单表 订单Id 商品Id 总金额 商品名称 001 1 10 苹果 001 2 10 橘子 联合主键订单Id、商品Id => 商品表 商品Id 商品名称 单价 订单表 订单Id 总金额 1.5.3 第三范式 1.5.3.1 规范 属性不依赖于其它非主属性,确保数据表中的每一列数据都和主键直接相关,而不能间接相关,即要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。 1.5.3.2 举例 党员表 党员Id 党员姓名 组织Code 符合3NF 党员表 党员Id 党员姓名 组织名称 不符合3NF 组织表 组织Code 组织名称 1.6 外连接 1.6.1 准备 create table student_A( uuid varchar2(32), name varchar2(100)); create table student_B( uuid varchar2(32), name varchar2(100)); insert into student_A values('1','小黄'); insert into student_A values('2','小黑'); insert into student_A values('3','小红'); insert into student_B values('1','大黄'); insert into student_B values('2','大黑'); insert into student_B values('4','大红'); insert into student_B values('4','大紫'); 1.6.2 左连接(left join) 1.6.2.1 说明 查询指定的左表的所有行,而不仅仅是联接列所匹配的行;如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。 1.6.2.2 语法 select A.*,B.* from student_A A left join student_B B on A.Uuid = B.Uuid; 1.6.2.3 结果 1.6.2.4 (+)表示 select A.*,B.* from student_A A,student_B B where A.Uuid = B.Uuid(+) 1.6.3 右连接(right join) 1.6.3.1 说明 查询指定的右表的所有行,而不仅仅是联接列所匹配的行;如果右表的某行在左表中没有匹配行,则在相关联的结果集行中左表的所有选择列表列均为空值。 1.6.3.2 语法 select A.*,B.* from student_A A right join student_B B on A.Uuid = B.Uuid; 1.6.3.3 结果 1.6.3.4 (+)表示 select A.*,B.* from student_A A,student_B B where A.Uuid(+) = B.Uuid 1.6.4 全外连接(full outer join) 1.6.4.1 说明 完整外部联接返回左表和右表中的所有行;当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值;如果表之间有匹配行,则整个结果集行包含基表的数据值。 1.6.4.2 语法 select A.*, B.* from student_A A full outer join student_B B on A.Uuid = B.Uuid; 1.6.4.3 结果 1.6.4.4 全外连接不支持(+)写法 1.6.5 (+) + 表示补充,即哪个表有加号,这个表就是匹配表。 1.7 运算符 1.7.1 比较 =、>,<,>=,<=,!=,<>, 1.7.2 确定范围 between and 、not between and 1.7.3 确定集合 in、not in 1.7.4 字符匹配 like(“%”匹配任何长度,“_”匹配一个字符) 1.7.5 转义字符 1.7.5.1 常规转义字符 “\”转义字符,“\%”则表示单纯的字符“%” 1.7.5.2 escape escape关键字经常用于使某些特殊字符,如通配符:'%','_'转义为它们原来的字符的意义,被定义的转义字符通常使用'\',但是也可以使用其他的符号。 select * from Student_a where name like '%$%%' escape '$'; 1.7.6 空值 is null、is not null 1.7.7 集合查询 union(并)、intersect(交)、minus(差) 1.7.8 多重条件 and、or、not 1.7.9 对查询结果分组 <group by 列名> 1.7.10 分组筛选条件 [having <条件表达式>] 1.7.11 字符串拼接 select 'A' || 'B' from dual; // || 拼接 1.8 函数 1.8.1 聚集函数 count、sum、avg、max、min 1.8.2 case when 1.8.2.1 语法 select t.uuid, t.score, case when t.score > 90 then '优秀' when t.score > 60 then '及格' else '不及格' end from exam_user_exam t 1.8.3 decode 1.8.3.1 语法 select decode(x,1,'x is 1', 2 , 'x is 2','others') from dual 1.8.3.2 说明 当x等于1时,则返回‘x is 1’,当x等于2时,则返回‘x is 2’,否则,返回‘others’。 1.8.4 nulls first(nulls last)排序 1.8.4.1 语法 select * from dy_info t order by t.degree nulls first 1.8.4.2 说明 控制null显示行位置 1.8.5 Nvl 1.8.5.1 语法 select nvl(t.sap,'空') from dy_info t; 1.8.5.2 说明 如果sap号为空,则返回‘空’,否则返回sap号。 1.8.6 递归查询 1.8.6.1 语法 select t.* from g_organ t start with t.organcode = '080' connect by prior t.parentcode = t.organcode; //递归查询父节点 select t.* from g_organ t start with t.organcode = '080' connect by t.parentcode = prior t.organcode; //递归查询子节点 1.8.7 union 和 union all 1.8.7.1 语法 select * from dual union all select * from dual 1.8.7.2 说明 union 会对查询数据进行去重并排序,union all只是简单的将两个结果合并。 1.8.8 wm_concat 1.8.8.1 语法 select wm_concat(t.role_name) from g_role t where t.role_name like '%书记%' 1.8.8.2 说明 拼接字符串,结果为:‘党工委副书记,总支副书记,党支部书记,党委书记,党委副书记,党总支书记,党工委书记,党总支副书记,党支部副书记’ 1.8.9 相似度 1.8.9.1 语法 select utl_match.edit_distance_similarity('aaaaa','bbaaaa') from dual; 1.8.10 去格式 1.8.10.1 oracle正则表达式:去除<></>格式 select REGEXP_REPLACE(title,'<[^>]*>','') title from exam_question 1.8.11 rank() over (partition by …) 1.8.11.1 语法 select organcode,score,ranknum from ( select t.organcode, t.score, rank() over (partition by t.organcode order by t.score desc) ranknum from exam_user_exam t) where ranknum < 4 1.8.11.2 说明 获取每个组织,考试成绩前三名。 1.9 存储过程 1.9.1 定义 存储过程是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。 1.9.2 准备 create table t_user ( username varchar2(20), password varchar2(20) ); create table t_user_temp ( username varchar2(20), password varchar2(20) ); insert into t_user(username,password) values('小王','1111'); insert into t_user(username,password) values('小李','1111'); 1.9.3 创建存储过程 create or replace procedure adduser as begin insert into t_user_temp(username,password) select username,password from t_user t where t.username = '小李'; end adduser; 1.9.4 执行 begin adduser; end; 1.9.5 验证 select * from t_user; select * from t_user_temp 2 SQL深入 2.1 常用 2.1.1 表空间 2.1.1.1 创建表空间 create tablespace TS_DJY datafile 'd:/software/oracle/tablespace/ts_djy.dat' size 1024M autoextend on next 100M maxsize 2048M; 2.1.1.2 指定用户表空间 alter user cssdj default tablespace TS_DJY; 2.1.1.3 指定表的表空间 create table t_student( uuid varchar2(32) )tablespace TS_DJY; 2.1.2 自增sequence 2.1.2.1 创建 create sequence seq_student_uuid minvalue 1 maxvalue 999999999999999 start with 1 increment by 1 nocache; 2.1.2.2 使用 select seq_student_uuid.nextval from dual; //获取下一个 select seq_student_uuid.currval from dual; //获取当前 2.1.3 批量插入 2.1.3.1 查询结果批量插入 insert into tablea(cola,colb) select cola,colb from tableb; 2.1.3.2 创建相同的表结构并插入数据(备份表数据) create tab_new as select * from tab_old; 2.1.3.3 创建相同的表结构不插入数据 create tab_new as select * from tab_old where rownum=0; 2.1.4 伪列伪表 2.1.4.1 伪列 伪列不是表的真实列,但是你可以象使用真实列一样使用伪列,常用伪列:rowid行的绝对物理编号,每一行是唯一的。rownum序号,返回查询结果的每行序号。系统时间sysdate,返回系统当前时间。 2.1.4.2 伪表 select * from dual; 2.1.5 系统表 2.1.5.1 user_tables 当前用户表信息 2.1.5.2 user_tab_columns 当前用户表所有列信息,搜索列所在的表: select * from user_tab_columns t where t.column_name like '%ORGANCODE%'; 2.1.5.3 user_tablespaces 当前用户表空间 2.1.5.4 dba_users 数据库所有用户 2.1.5.5 dba_tables 数据库所有表 2.1.5.6 dba_tablespaces 数据库所有表空间 2.1.6 锁表解锁 2.1.6.1 查看锁表信息 select l.OBJECT_ID,s.SID,s.SERIAL#,s.USERNAME, s.MACHINE from V$locked_Object l,V$session s where l.SESSION_ID = s.SID; 2.1.6.2 解锁 alter system kill session 'sid,serial#'; 2.1.7 备份与恢复 2.1.7.1 导出 导出用户: exp cssdj/cssdj@zr owner=(cssdj,cssdj_zsy) file=d:/cssdj.dmp log=d:/cssdj.log 导出用户表: exp cssdj/cssdj@zr tables=(g_dict,g_dict_item) file=d:/cssdj.dmp log=d:/cssdl.log 2.1.7.2 导入 imp cssdj/cssdj@zr fromuser=cssdj_zsy touser=cssdj file=d:/cssdj.cmp log=d:/cssdj.log 2.1.7.3 数据泵 2.1.8 Dblink 2.1.8.1 创建 create database link orcllink connect to cssdj identified by cssdj using '(DESCRIPTION = (ADDRESS_LIST= (ADDRESS=(PROTOCOL = TCP)(HOST = 219.239.110.65)(PORT = 1521))) (CONNECT_DATA=(SID = orcl)))'; 2.1.8.2 删除 drop database link orcllink; 2.1.8.3 使用 select * from dy_info@orcllink; 2.2 Oracle与Mysql差异 2.2.1 Group by 2.2.1.1 Oracle select后面出现的列,如果没有使用集合函数,必须出现在group by 中。 select sno,sname,sum(grade) from student group by sno,sname; //合法写法 select sno,sname,sum(grade) from student group by sno; //非法写法 select sno,min(sname),sum(grade) from student group by sno; //建议用这种写法,效率高些 2.2.1.2 Mysql select sno,sname,sum(grade) from student group by sno,sname; //合法写法 select sno,sname,sum(grade) from student group by sno; //合法写法 2.2.2 分页 2.2.2.1 Oracle 使用rownum来表明分页位置,而且rownum只能小于某值,不能大于某值,故而rownum和where联用才能完成数据范围的控制 2.2.2.2 Mysql mysql的分页可以用limit startNum,pageNum 2.3 了解 2.3.1 事务 2.3.1.1 Rollback start transaction; --开始事务 insert into g_dict values('test','测试','1',''); --执行数据操作语言(DML) select * from g_dict where code = 'test'; --可以查看是否执行正确 rollback; --错误执行rollback操作 commit; --正确执行commit操作 2.3.1.2 Savepoint start transaction; --开始事务 insert into g_dict values('t1','测试','1',''); --执行数据操作语言(DML) savepoint pointA; insert into g_dict values('t2','测试','1',''); --执行数据操作语言(DML) select * from g_dict where code = 'test33'; --可以查看是否执行正确 rollback to savepoint pointA; 2.3.2 利用执行计划评估SQL语句的性能 2.3.2.1 工具 在PL/SQL Developer中写好一段SQL代码后,按F5,PL/SQL Developer会自动打开执行计划窗口,显示该SQL的执行计划。 2.3.2.2 查看总COST,获得资源耗费的总体印象 一般而言,执行计划第一行所对应的COST(即成本耗费)值,反应了运行这段SQL的总体估计成本,单看这个总成本没有实际意义,但可以拿它与相同逻辑不同执行计划的SQL的总体COST进行比较,通常COST低的执行计划要好一些。 2.3.2.3 了解执行计划的执行步骤 按照从左至右,从上至下的方法,了解执行计划的执行步骤; 执行计划按照层次逐步缩进,从左至右看,缩进最多的那一步,最先执行,如果缩进量相同,则按照从上而下的方法判断执行顺序,可粗略认为上面的步骤优先执行。每一个执行步骤都有对应的COST,可从单步COST的高低,以及单步的估计结果集(对应ROWS/基数),来分析表的访问方式,连接顺序以及连接方式是否合理。 2.3.2.4 分析表的访问方式 表的访问方式主要是两种:全表扫描(TABLE ACCESS FULL)和索引扫描(INDEX SCAN),如果表上存在选择性很好的索引,却走了全表扫描,而且是大表的全表扫描,就说明表的访问方式可能存在问题;若大表上没有合适的索引而走了全表扫描,就需要分析能否建立索引,或者是否能选择更合适的表连接方式和连接顺序以提高效率。 2.3.2.5 分析表的连接方式和连接顺序 表的连接顺序:就是以哪张表作为驱动表来连接其他表的先后访问顺序。 表的连接方式:简单来讲,就是两个表获得满足条件的数据时的连接过程。主要有三种表连接方式,嵌套循环(NESTED LOOPS)、哈希连接(HASH JOIN)和排序-合并连接(SORT MERGE JOIN)。我们常见得是嵌套循环和哈希连接。 嵌套循环:最适用也是最简单的连接方式。类似于用两层循环处理两个游标,外层游标称作驱动表,Oracle检索驱动表的数据,一条一条的代入内层游标,查找满足WHERE条件的所有数据,因此内层游标表中可用索引的选择性越好,嵌套循环连接的性能就越高。 哈希连接:先将驱动表的数据按照条件字段以散列的方式放入内存,然后在内存中匹配满足条件的行。哈希连接需要有合适的内存,而且必须在CBO优化模式下,连接两表的WHERE条件有等号的情况下才可以使用。哈希连接在表的数据量较大,表中没有合适的索引可用时比嵌套循环的效率要高。 2.3.3 优化器 Oracle优化器分为基于规则的优化器(RBO)和基于代价的优化器(CBO)。 2.3.3.1 规则的优化器(RBO) RBO的优化方式,依赖于一套严格的语法规则,只要按照规则写出的语句,不管数据表和索引的内容是否发生变化,不会影响PL/SQL语句的"执行计划"。 2.3.3.2 基于代价的优化器(CBO) CBO计算各种可能"执行计划"的"代价",即cost,从中选用cost最低的方案,作为实际运行方案。各"执行计划"的cost的计算根据,依赖于数据表中数据的统计分布,ORACLE数据库本身对该统计分布是不清楚的,须要分析表和相关的索引,才能搜集到CBO所需的数据。 2.3.4 表分析analysis 2.3.4.1 说明 analyze table,一般可以指定分析表、所有字段、所有索引字段、所有索引,若不指定则全部都分析。 2.3.4.2 表分析 analyze table dy_info compute statistics; 2.3.4.3 删除分析数据 analyze table dy_info delete statistics; 2.3.5 oracle添加强制索引 如果使用的是CBO的话,可能SQL不执行索引,则可以添加强制索引执行索引。 2.3.5.1 语法 /*+index(tablename indexname)*/ 2.3.5.2 举例 select /*+index(t INDEX_SAP)*/* from dy_info t where t.sap = 'T6000890'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值